<?php


namespace app\common\model;


use think\Db;
use think\Exception;

class AgentShare
{
    //查询分账返回结果
    public static function checkFen($data,$model = '')
    {
        $url = 'https://pay.51wanquan.com/api/sharing/inquiry';
        $option = [
            'mchId' => $data['mchId'],
            'mchSharingNo' => $data['fen_sn'],
        ];
        $row = AgentShare::requestJavaAPIV2($url,$option);
        //print_r($row);
        if($model){
            $res = RechargeBill::get($data['id']);
        }else{
            $res = BillLog::get($data['id']);
        }
        if(!empty($row['msg']) && $row['msg'] == 'SUCCESS'){
            $apidata = json_decode($row['data']['receivers'],true);
            foreach($apidata as $v){
                if($v['sharingStatus'] == 'SUCCESS'){
                    $res->is_success = 1;
                }
            }
            $res->is_check = 1;
            $res->check_json = json_encode($row,JSON_UNESCAPED_UNICODE);
            $res->save();
        }else{
            $res->is_check = 1;
            $res->check_json = json_encode($row,JSON_UNESCAPED_UNICODE);
            $res->save();
        }
        /*Array
(
    [code] => 200
    [msg] => SUCCESS
    [data] => Array
        (
            [mchId] => 39497568
            [mchSharingNo] => F2022111657555097
            [transactionId] => M20221115799321683546316800
            [sharingNo] => S799441306451222529
            [status] => FINISHED
            [receivers] => [{"amount":82,"description":"fen","finishTime":"20221116005421","receiverId":"39753997","receiverType":"B","sharingStatus":"SUCCESS"}]
        )

    [nonceStr] => e813d36c74cf02d467867e5d4373d3c9
)*/
    }

    //发放分账
    public static function sendFen($data,$model = '')
    {
        //分账
        $fenUrl = 'https://pay.51wanquan.com/api/sharing';
        $amount = (int)floor($data['fen_fee']*100);
        $receivers = [
            [
                'receiverId' => $data['fz_number'],
                'receiverType' => "B",
                'amount' => $amount,
                "description" => "fen"
            ]// 最多5个
        ];
        self::bindAccount($data['mchId'],$data['fz_number']);
        $option = [
            "mchId" => $data['mchId'], //Excel第三列
            "mchSharingNo" => $data['fen_sn'], //自己生成的分账流水号
            "transactionId" => $data['chnltrxid'], //M开头
            "totalAmount" => $amount,  // 下面列表的总和。
            "receivers" => json_encode($receivers,JSON_UNESCAPED_UNICODE),
        ];
       /* print_r($data['id']);
        print_r($option);
        echo '--'.PHP_EOL;*/
        //只分钱包类型的
        $row = AgentShare::requestJavaAPIV2($fenUrl,$option);
        /*print_r($data);
        print_r($row);die();*/

        if($model){
            $res = RechargeBill::get($data['id']);
        }else{
            $res = BillLog::get($data['id']);
        }
        if(!empty($row['msg']) && $row['msg'] == 'SUCCESS'){
            $res->is_send = 1;
            $res->req_json = json_encode($row,JSON_UNESCAPED_UNICODE);
            $res->save();
        }else{
            $res->req_json = json_encode($row,JSON_UNESCAPED_UNICODE);
            $res->save();
        }
        /**
         * Array
        (
        [code] => 200
        [msg] => SUCCESS
        [data] => Array
        (
        [mchId] => 39497568
        [mchSharingNo] => F2022111657555097
        [transactionId] => M20221115799321683546316800
        [sharingNo] => S799441306451222529
        )
        [nonceStr] => 802019817403adfd67167d10c365717d
        )
         */
       /**/
        return ;
    }

    //查询可用分账金额
    public static function findFenMoney($mchId,$transactionId,$id = '')
    {
        $option = [
            "mchId" => $mchId,
            //"mchId" => '39497568', //翼龙的收单商户号  8为的数字
            "transactionId" => $transactionId,
            //"transactionId" => 'M20221115799314366096461825', //M开头的流水号
        ];
        //查询分账余额
        $url = 'https://pay.51wanquan.com/api/sharing/sharable-amount/inquiry';
        // 查询分账余额
        $row = AgentShare::requestJavaAPIV2($url,$option); //已调通*/
        //print_r($row);
        if(!empty($row['msg']) && $row['msg'] == 'SUCCESS'){
            //插入绑定关系
            $sharableAmount = $row['data']['sharableAmount']/100;
            if($sharableAmount){
                Db::table('recharge')
                    ->where("chnltrxid",$transactionId)
                    ->update(['sharableAmount'=>$sharableAmount]);
                log_print('查询分账余额');
                log_print( Db::table('recharge')->getLastSql());
            }
            return $sharableAmount;
        }else{
            log_print('查询分账金额出错$mchId='.$mchId.'-$transactionId'.$transactionId.'-bill_id'.$id);
            log_print($row);
            return 0;
        }

    }
    public static function checkFenMoney2($mchId,$transactionId)
    {
        $option = [
            "mchId" => $mchId,
            "transactionId" => $transactionId,
        ];
        //查询分账余额
        $url = 'https://pay.51wanquan.com/api/sharing/sharable-amount/inquiry';
        // 查询分账余额
        $row = AgentShare::requestJavaAPIV2($url,$option);

        if(!empty($row['msg']) && $row['msg'] == 'SUCCESS'){
            $sharableAmount = $row['data']['sharableAmount']/100;
            $up = [
                'check_amount'=>$sharableAmount,
                'check_json' => json_encode($row,JSON_UNESCAPED_UNICODE),
            ];

                $up += [
                    'is_check' => 1,
                    'updatetime' => time(),
                ];

            Db::table('recharge')
                ->where("chnltrxid",$transactionId)
                ->update($up);
            log_print('检测充值订单剩余分账金额'.Db::table('recharge')->getLastSql());
            return $sharableAmount;
        }else{
            $up = [
                'is_check' => 1,
                'check_json' => json_encode($row,JSON_UNESCAPED_UNICODE),
                'updatetime' => time(),
            ];
            Db::table('recharge')
                ->where("chnltrxid",$transactionId)
                ->update($up);
            log_print('查询分账金额出错$mchId='.$mchId.'-$transactionId'.$transactionId);
            log_print($row);
            return 0;
        }
    }
    //查询可用分账金额
    public static function checkFenMoney($mchId,$transactionId)
    {
        $option = [
            "mchId" => $mchId,
            "transactionId" => $transactionId,
        ];
        //查询分账余额
        $url = 'https://pay.51wanquan.com/api/sharing/sharable-amount/inquiry';
        // 查询分账余额
        $row = AgentShare::requestJavaAPIV2($url,$option);

        if(!empty($row['msg']) && $row['msg'] == 'SUCCESS'){
            $sharableAmount = $row['data']['sharableAmount']/100;
            $up = [
                'check_amount'=>$sharableAmount,
                'check_json' => json_encode($row,JSON_UNESCAPED_UNICODE),
            ];
            if($sharableAmount > 0.01){
                $up+=[
                    'is_fen' => 1,
                    'is_check' => 0,
                ];
            }else{
                $up += [
                    'is_check' => 1,
                ];
            }
            Db::table('recharge')
                    ->where("chnltrxid",$transactionId)
                    ->update($up);
            log_print('检测充值订单剩余分账金额'.Db::table('recharge')->getLastSql());
            return $sharableAmount;
        }else{
            $up = [
                'is_check' => 1,
                'check_json' => json_encode($row,JSON_UNESCAPED_UNICODE),
            ];
            Db::table('recharge')
                ->where("chnltrxid",$transactionId)
                ->update($up);
            log_print('查询分账金额出错$mchId='.$mchId.'-$transactionId'.$transactionId);
            log_print($row);
            return 0;
        }
    }

    //绑定分账账号
    public static function bindAccount($pay,$shou)
    {
        $map = [
            'pay_account' => $pay, //发放方商户
            'shou_account' => $shou,//接收方商户
        ];
        if($pay == $shou){
            return true;
        }
        $res = BindAccount::where($map)->find();
        if($res){
            return true;
        }
        $receiver= ["receiverType"=>"B","receiverId" => $shou];
        $option = [
            "mchId" => $pay,
            "receiver" => json_encode($receiver,true,JSON_UNESCAPED_UNICODE),//receiverId 读取
        ];
        //print_r($option);die();
        // 添加分账接收方
        $url = 'https://pay.51wanquan.com/api/sharing/receiver/bind';
        $row = AgentShare::requestJavaAPIV2($url,$option);   //维护绑定关系表
        //print_r($row);
        if(!empty($row['msg']) && $row['msg'] == 'SUCCESS'){
            //插入绑定关系
            $log = [
                'pay_account' => $pay,
                'shou_account' => $shou,
            ];
            BindAccount::create($log);
            log_print('绑定分账账号'.(new BindAccount())->getLastSql());
            return true;
        }else{
            log_print('账号绑定失败pay='.$pay.'-shou'.$shou);
            return false;
        }

    }

    /**
     * @param string $url
     * @param array $params
     * @param string $logDesc
     * @param bool $isRaw 是否为原始数据流，直接返回，不做后续处理
     * @return array|mixed
     * @throws SysException
     * @throws \Throwable
     */
    public static function requestJavaAPIV2(string $url, array $params = [])
    {
        $headers = [
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
            'Authorization' => '',
        ];
        $signStr = '';
        try {
            $appid = config('thirdpay.fenpay')['appId'];
            $nonceStr = md5(uniqid());
            //$timestamp = time();
            $timestamp = intval(microtime(true) * 1000);
            list($s1, $s2) = explode(' ', microtime());
            $timestamp = (float)sprintf('%.0f', (floatval($s1) + floatval($s2)) * 1000);
            //echo '请求参数'.PHP_EOL;
            //print_r($params);
            $urlPath = parse_url($url, PHP_URL_PATH);
            // 目前采用的远程类在发送json时，会对字符串的特殊字符编码处理 HttpClientTrait::jsonEncode
            $signStr = "POST\n{$urlPath}\n{$timestamp}\n{$nonceStr}\n" . json_encode($params) . "\n";
           /* if(isset($params['receiver'])){
                $params['receiver'] = json_encode($params['receiver']);
            }*/
            //print_r($params);
            //echo $signStr;die();
            if (!openssl_sign($signStr, $sign, self::getSignKey(), OPENSSL_ALGO_SHA256)) {
                $msgParams = 'Err: ' . openssl_error_string();
                throw new Exception($msgParams);
            }

            $signBase64 = base64_encode($sign);

            $authorizationStr = "{$appid}:{$nonceStr}:RSA2:{$timestamp}:{$signBase64}";
            //echo $authorizationStr.PHP_EOL;
            $headers['Authorization'] = "{$authorizationStr}";
            //echo '请求header'.PHP_EOL;
            //print_r($headers);
            //die();
            $respJSONDecode = self::postRequest($url,$params,$headers);
            return $respJSONDecode;
           // echo PHP_EOL.'返回结果';
            //print_r($respJSONDecode);die();
            if ($respJSONDecode['code'] != '200') {
                $msgParams = "Err: {$respJSONDecode['code']}::{$respJSONDecode['msg']}";
                throw new Exception($msgParams);
            }

            if (!isset($respJSONDecode['data'])) {
                throw new Exception($respJSONDecode);
            }
            return $respJSONDecode['data'];
        } catch (Exception $e) {
            log_print('请求分账接口抛出异常');
            log_print($url);
            log_print($params);
            log_print($e->getMessage());
            //ECHO '12';
            throw $e;
        }
    }


    public static function postRequest($url,$option,$header = [])
    {
        $client = new \GuzzleHttp\Client();
        //print_r($header);die();
        $res = $client->request('POST', $url, [
            'json' => $option,
            'headers' => $header
        ]);
       /* echo '请求参数'.PHP_EOL;
        print_r($option);
        echo '请求header'.PHP_EOL;
        print_r($header);DIE();*/
        $req = $res->getBody()->getContents();
        $api_data = json_decode($req, true);
        return $api_data;
    }

    /**
     * 响应验签
     *
     * @param $respData
     * @param array $respHeaders
     * @throws SysException
     */
    private static function verifyResponseSign($respData, array $respHeaders)
    {
        $respVerifySign = '';
        foreach ($respHeaders as $headerKey => $headerValue) {
            $headerKey = strtolower(trim($headerKey));
            if ($headerKey == 'response-signature') {
                $respVerifySign = trim(array_shift($headerValue));
                break;
            }
        }

        if (!$respVerifySign) {
            //throw new SysException(RespCons::UPSTREAM_RESPONSE_SIGN_INVALID);
            throw new Exception('签名无效');
        }

        $extractData = UtilHelper::extractStringToStringArray($respVerifySign, ':', true, false, 3);
        if (count($extractData) < 3) {
            //throw new SysException(RespCons::UPSTREAM_RESPONSE_SIGN_FORMAT_ERR);
            throw new Exception('签名格式错误');
        }

        list($nonceStr, $timestamp, $sign) = $extractData;
        if (empty($nonceStr) || empty($timestamp) || empty($sign)) {
            //throw new SysException(RespCons::UPSTREAM_RESPONSE_SIGN_DATA_ERR);
            throw new Exception('缺少参数');
        }

        $signBinary = base64_decode($sign);
        if (!$signBinary) {
            //throw new SysException(RespCons::UPSTREAM_RESPONSE_SIGN_DATA_ERR);
            throw new Exception('发送的响应数据错误');
        }

        $signStr = "{$nonceStr}\n{$timestamp}\n{$respData}\n";
        if (!openssl_verify($signStr, $signBinary, self::getVerifyKey(), OPENSSL_ALGO_SHA256)) {
            $msgParams = 'Err: ' . openssl_error_string();
            //throw new SysException(RespCons::RSA_VERIFY_SIGN_FAIL, '', $msgParams);
            throw new Exception('签名验证失败'.$msgParams);
        }
    }

    /**
     * 获取验签公钥
     *
     * @return \OpenSSLAsymmetricKey
     * @throws SysException
     */
    private static function getVerifyKey()
    {
        $publicKey = config('java.pay_v2.verify_public');
        $publicKey = config('thirdpay.fenpay')['publickey'];
        if (!$publicKey) {
            throw new SysException(RespCons::RSA_KEY_NOT_EXIST);
        }

        $publicKeyReal = "-----BEGIN PUBLIC KEY-----\n";
        $publicKeyReal .= wordwrap($publicKey, 64, "\n", true);
        $publicKeyReal .= "\n-----END PUBLIC KEY-----";

        $keyRes = openssl_pkey_get_public($publicKeyReal);
        if ($keyRes === false) {
            $msgParams = 'Err: ' . openssl_error_string();
            throw new Exception('无效的签名秘钥'.$msgParams);
        }

        return $keyRes;
    }

    /**
     * 获取签名私钥
     *
     * @return \OpenSSLAsymmetricKey
     * @throws SysException
     */
    private static function getSignKey()
    {
        $privateKey = config('thirdpay.fenpay')['privatekey'];
        //var_dump($privateKey);die();
        if (!$privateKey) {
            throw new Exception('签名秘钥不存在');
            //throw new SysException(RespCons::RSA_KEY_NOT_EXIST);
        }

        $privateKeyReal = "-----BEGIN RSA PRIVATE KEY-----\n";
        $privateKeyReal .= wordwrap($privateKey, 64, "\n", true);
        $privateKeyReal .= "\n-----END RSA PRIVATE KEY-----";

        $keyRes = openssl_pkey_get_private($privateKeyReal);
        if ($keyRes === false) {
            $msgParams = 'Err: ' . openssl_error_string();
            throw new Exception('无效的签名秘钥'.$msgParams);
        }
        return $keyRes;
    }


    /**
     * JSON 编码
     *
     * @param $value
     * @param int|null $flags
     * @param bool $mergeFlag $flags 不为 null 时，是否与默认 HEX 选项合并或运算
     * @param int $maxDepth
     * @return string
     * @throws SysException
     */
    private static function jsonEncode($value, int $flags = null, bool $mergeFlag = false, int $maxDepth = 512): string
    {
        static $defaultOptions = \JSON_HEX_TAG | \JSON_HEX_APOS | \JSON_HEX_AMP | \JSON_HEX_QUOT | \JSON_PRESERVE_ZERO_FRACTION;
        if ($flags !== null) {
            $flags = $mergeFlag ? $flags | $defaultOptions : $flags;
        } else {
            $flags = $defaultOptions;
        }
        $value = json_encode($value, $flags | (\PHP_VERSION_ID >= 70300 ? \JSON_THROW_ON_ERROR : 0), $maxDepth);
        return $value;
    }
}
